/**
 * Description:
 * Class Name:ThreadPoolAIOClient
 * Date:2022/5/26 18:41
 *
 * @author LTisme
 * @version JAVA17
 */
package 疯狂Java讲义.第17章_网络编程._17_3_基于TCP协议的网络编程._17_3_8_使用AIO实现非阻塞通信;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolAIOClient {
    final static int PORT = 30000;
    // 与服务器端通信的异步Channel
    AsynchronousSocketChannel clientChannel;

    JFrame mainWin = new JFrame("多人聊天");
    JTextArea jTextArea = new JTextArea(16, 48);
    JTextField jTextField = new JTextField(40);
    JButton sendBn = new JButton("发送");
    public void init(){
        mainWin.setLayout(new BorderLayout());
        jTextArea.setEditable(false);
        mainWin.add(new JScrollPane(jTextArea), BorderLayout.CENTER);
        var jp = new JPanel();
        jp.add(jTextField);
        jp.add(sendBn);

        // 发送消息的Action，Action是ActionListener的子接口；它是为sendBn准备的动作
        var sendAction = new AbstractAction(){
            public void actionPerformed(ActionEvent e){
                String content = jTextField.getText();
                if (content.trim().length() > 0){
                    try {
                        // 将content内容写入Channel中
                        clientChannel.write(ByteBuffer.wrap(content.trim().getBytes(StandardCharsets.UTF_8))).get();
                    }
                    catch (Exception ex){
                        ex.printStackTrace();
                    }
                }
                // 清空输入框
                jTextField.setText("");
            }
        };
        sendBn.addActionListener(sendAction);
        // 将“Ctrl+Enter”键与"send"关联
        jTextField.getInputMap().put(KeyStroke.getKeyStroke('\n', InputEvent.CTRL_DOWN_MASK), "send");
        // 将"send"与sendAction相关联
        jTextField.getActionMap().put("send", sendAction);;
        mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainWin.add(jp, BorderLayout.SOUTH);
        mainWin.pack();
        mainWin.setVisible(true);
    }

    public void connect() throws Exception{
        // 定义一个ByteBuffer来读取数据
        final ByteBuffer buffer = ByteBuffer.allocate(1024);
        // 也创建一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(80);
        // 以指定线程池来创建一个AsynchronousChannelGroup
        AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(executor);
        // 也分为3步，open()、connect()、read() or write()
        clientChannel = AsynchronousSocketChannel.open(channelGroup);
        clientChannel.connect(new InetSocketAddress("loca" +
                "" +
                "" +
                "lhost", PORT)).get();
        jTextArea.append("---与服务器连接成功---\n");
        buffer.clear();
        clientChannel.read(buffer, null, new CompletionHandler<Integer, Object>() {
            @Override
            public void completed(Integer result, Object attachment) {
                buffer.flip();
                // 将buff中的内容转换成字符串
                String content = StandardCharsets.UTF_8.decode(buffer).toString();
                // 现实从服务器端读取的数据
                jTextArea.append("某人说：" + content + "\n");
                buffer.clear();
                clientChannel.read(buffer, null, this);
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                System.out.println("读取数据失败：" + exc);
            }
        });
    }

    public static void main(String[] args) throws Exception{
        var client = new ThreadPoolAIOClient();
        client.init();
        client.connect();
    }
}
